// Fill out your copyright notice in the Description page of Project Settings.


#include "Algorithm/MazeCreator/DFSCreator.h"

#include "Kismet/KismetMathLibrary.h"

ADFSCreator::ADFSCreator()
{
	PrimaryActorTick.bCanEverTick = false;
}

void ADFSCreator::CreateMaze()
{
	roadArr = TArray<TArray<int32>>();
	TArray<int32> temp = TArray<int32>();
	temp.Init(0, height);
	roadArr.Init(temp, width);
	//初始化
	for (int32 i = 0; i < width; i++)
	{
		for (int32 j = 0; j < height; j++)
		{
			UStaticMeshComponent* smComp = NewObject<UStaticMeshComponent>(this);
			smComp->SetupAttachment(GetRootComponent());
			smComp->RegisterComponent();
			smComp->SetRelativeScale3D(FVector(1.0f));
			smComp->SetRelativeLocation(FVector((j - (int32)height / 2) * 100, (i - (int32)width / 2) * 100, 0));

			//判断是否可以作为道路点
			bool bCanBeRoad = (i % 2) && (j % 2) && i * j != 0 && i != height - 1 && j != width - 1;
			roadArr[i][j] = (int32)bCanBeRoad;
			smComp->SetStaticMesh(bCanBeRoad ? PlaneMesh : BlockMesh);
			roadrMeshs.Add(smComp);
		}
	}
	DFSFindPath(1, 1); // 搜索
	GetWorld()->GetTimerManager().SetTimer(timerHandle, this, &ADFSCreator::ChangeMesh, playRate, true, 1);
}

void ADFSCreator::DFSFindPath(int32 x, int32 y)
{
	roadArr[x][y] = 2;
	taskQueue.Enqueue(TTuple<int32, int32>(x, y));

	TArray<int32> offsetX = {-1, 0, 1, 0};
	TArray<int32> offsetY = {0, -1, 0, 1};
	int32 randomInt = UKismetMathLibrary::RandomInteger(4); //随机某个方向开始
	for (int32 j = randomInt; j < randomInt + 4; ++j)
	{
		int32 i = j % 4;
		if (checkPointValid(x + offsetX[i] * 2, y + offsetY[i] * 2))
		{
			roadArr[x + offsetX[i]][y + offsetY[i]] = 2;
			taskQueue.Enqueue(TTuple<int32, int32>(x + offsetX[i], y + offsetY[i]));
			DFSFindPath(x + offsetX[i] * 2, y + offsetY[i] * 2);
		}
	}
}

bool ADFSCreator::checkPointValid(int32 x, int32 y)
{
	return (0 < x && x < width - 1) && (0 < y && y < height - 1) && roadArr[x][y] == 1;
}

void ADFSCreator::ChangeMesh()
{
	TTuple<int32, int32> point;
	if (taskQueue.Dequeue(point) && roadrMeshs.Num() > 0)
	{
		if (roadrMeshs[point.Get<0>() * height + point.Get<1>()])
		{
			roadrMeshs[point.Get<0>() * height + point.Get<1>()]->SetStaticMesh(PlaneMesh);
			roadrMeshs[point.Get<0>() * height + point.Get<1>()]->AddRelativeLocation(FVector(0, 0, -50));
		}
	}
}

void ADFSCreator::BeginPlay()
{
	Super::BeginPlay();
	CreateMaze();
}
